/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package CastleDefense.units;

import CastleDefense.Animation;
import CastleDefense.Enemy;
import CastleDefense.Enemy.MonsterType;
import CastleDefense.Game;
import CastleDefense.Managers.GameManager;
import CastleDefense.Managers.UnitManager;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.vecmath.Vector2d;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author Administrator
 */
public class PlacedUnit
{
    public enum StateEffect { NONE, SLOW, SPLASH, SNARE, POISON }

    //basics
    private Image    sprite;
    private Enemy    target;
    private Vector2d location;
    private String   projectile;
    private String   unitName    = "";
    private String   unitClass   = "";
    private Unit     unit;
    
    //stats
    protected long    rateOfFire;
    protected long    lastFire   = 0;
    protected double  range;
    protected double  targetD;
    protected double  damage;
    protected double  atkMod;
    protected double  cashValue;
    public    double  tempDist;
    protected int     kills      = 0;
    protected boolean runLogic;

    //animation
    protected Image[] frames     = new Image[2];
    private Animation anim;

    //collision
    private Rectangle me         = new Rectangle();
    private Rectangle him        = new Rectangle();
    
    public PlacedUnit(Vector2d loc, Image img, String name)
    {     
        this.unit       = UnitManager.getInstance().getUnitList().getUnitByName(name);
        
        this.range      = unit.getRange();
        this.sprite     = img;
        this.damage     = unit.getDamage();
        this.atkMod     = unit.getAtkmod();
        this.unitName   = name;
        this.location   = loc;
        this.runLogic   = true;
        this.cashValue  = unit.getCost();
        this.unitClass  = unit.getUclass();
        this.rateOfFire = unit.getRof();
        this.projectile = unit.getProj();
    }

    public PlacedUnit(Vector2d loc, Image img)
    {     
        this.sprite     = img;
        this.location   = loc;
        this.runLogic   = false;
    }
    
    public void doLogic()
    {
        //non specific units
        if(runLogic)
            if(target != null && !target.isDead()) //tries to fireEnemy at a target
            {
                targetD = distance(location.x, location.y, target.getMidX(), target.getMidY());
                if(targetD > range)
                {
                    setClosestTarget();
                    return;
                }

                if(System.currentTimeMillis() - lastFire < rateOfFire)
                    return;

                lastFire = System.currentTimeMillis();
                Game.fireAtEnemy(target, this);
            }
            else if(target == null || target.isDead())  //sets target if no target has been set
            {
                setClosestTarget();
            }
            else //resets a target if it is too far away
            {
                setClosestTarget();
            }
    }

    /**
     *
     *
     */
    protected void setClosestTarget()
    {
        target         = null;
        double dist;
        double minDist = Double.MAX_VALUE;
        ArrayList<Enemy> enemies = Game.getEnemyList();
        
        for (Enemy enemy : enemies)
        {
            if(this.getName().equals("Blowgunist"))
            {
                if(!enemy.isPoisoned())
                {
                    dist = this.distance(this.getX(), this.getY(), enemy.getX(), enemy.getY());
                    if (dist < this.getRange() && dist < minDist)
                    {
                        minDist = dist;
                        target  = enemy;
                    }
                }
            }
            else
            {
                dist = this.distance(this.getX(), this.getY(), enemy.getX(), enemy.getY());
                if (dist < this.getRange() && dist < minDist)
                {
                    minDist = dist;
                    target  = enemy;
                }
            }
        }
    }

    protected boolean collidesWith(Enemy e)
    {
        me.setBounds(getX(), getY(), sprite.getWidth(null), sprite.getHeight(null));
        him.setBounds((int) e.getX(), (int) e.getY(), e.getSprite().getWidth(), e.getSprite().getHeight());
        
        return me.intersects(him);
    }

    protected boolean damagesTarget(Enemy e)
    {
        String uc = this.getUnitClass();
        if(e.getMobType() == MonsterType.FLYING && uc.equals("Traps"))
            return false;
        else if(e.getMobType() == MonsterType.GHOST && !uc.equals("Magic"))
            return false;
        else if(e.getMobType() == MonsterType.MAGIC_IMMUNE && uc.equals("Magic"))
            return false;

        return true;
    }

    protected boolean killsTarget(int chance)
    {
        if(chance>100)
            chance = 100;

        Random rand = new Random();

        return (rand.nextInt(100) < chance) ? true : false;
    }

    public ArrayList<Image> getAnimation(String name)
    {
        ArrayList<Image> aFrames     = new ArrayList<Image>();
        String           sprites     = unit.getSprite();
        String[]         spriteArray = StringUtils.splitPreserveAllTokens(sprites, ',');

        for(String spriteName : spriteArray)
        {
            Image temp = new ImageIcon(this.getClass().getResource("../"+GameManager.getInstance().UNITS_PATH() + spriteName)).getImage();
            aFrames.add(temp);
        }

        return aFrames;
    }

    public String getUnitEffect()
    {
        int[]  unitEffects = unit.getStateEffects();
        String effects     = "";

        for(int effect : unitEffects)
        {
            effects += (getEffectName(effect)+", ");
        }

        return effects.substring(0, effects.lastIndexOf(',', effects.lastIndexOf(',')));
    }

    private String getEffectName(int id)
    {
        switch(id)
        {
            case 0:
                return "No Effect";
            case 1:
                return "Slows";
            case 2:
                return "Splashes";
            case 3:
                return "Snares";
            case 4:
                return "Poisons";
            default:
                return "No Effect";
        }
    }

    public double distance(double x1, double y1, double x2, double y2)
    {
        Point2D p1, p2;
        double distance;

        p1 = new Point2D.Double(x1+21, y1+21);
        p2 = new Point2D.Double(x2+21, y2+21);

        distance = p1.distance(p2);

        return distance;
    }
    
    /**
     *
     */
    public Image getSprite()
    {
        return sprite;
    }

    public Animation getAnim()
    {
        return anim;
    }

    public void setAnimation(Animation anim)
    {
        this.anim = anim;
    }

    public void setSprite(Image spr)
    {
        this.sprite = spr;
    }

    public Vector2d getLoc()
    {
        return location;
    }

    public int getX()
    {
        return (int)location.x;
    }

    public int getY()
    {
        return (int)location.y;
    }

    public int getMidX()
    {
        return (int)(location.x+21);
    }

    public int getMidY()
    {
        return (int)(location.y+21);
    }

    public double getRange()
    {
        return range;
    }

    public String getName()
    {
        return unitName;
    }
    
    public String getProj()
    {
        return projectile;
    }

    public PlacedUnit getPUnit()
    {
        return this;
    }

    public String getUnitClass()
    {
        return unitClass;
    }

    public double getDamage()
    {
        return damage;
    }

    public double getAtkMod()
    {
        return atkMod;
    }

    public double getSaleValue()
    {
        int myKills = getMyKills();

        if(myKills>=175)
            return (cashValue*3);
        else if(myKills>=75)
            return (cashValue*2);
        else if(myKills>=25)
            return (cashValue*1);
        else
            return (cashValue/2);
    }

    public Enemy getTarget()
    {
        return target;
    }

    public void setTarget(Enemy e)
    {
        this.target = e;
    }

    public int getMyKills()
    {
        return kills;
    }

    public void addUnitKills()
    {
        this.kills++;
    }
}
